package com.googlecode.dgwt.client.dijit.base.manager;

import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.impl.FocusImpl;
import com.google.gwt.user.client.ui.impl.FocusImplOld;
import com.googlecode.dgwt.client.dijit.Widget;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public class PanelFocusManager extends FocusManager {
    /*
    private static final String OWNER_WIDGET_PROPERTY = "__dijitPanelFocusManager_ownerWidget";

    private static final String LAST_FOCUS_EVENT_PROPERTY = "__dijitPanelFocusManager_lastFocusEvent";

    private static final String LAST_BLUR_EVENT_PROPERTY = "__dijitPanelFocusManager_lastBlurEvent";
    
    private static final String WAITING_PROPERTY = "__dijitPanelFocusManager_waiting";
    
    private static final int WAINTING_FOR_FOCUS = 1;
    
    private static final int WAINTING_FOR_BLUR = 2;
    */
    private static PanelFocusManager focusManager; 
    
    
    //private Widget focusedWidget;
    
    //private JsObject nativeHandler;

    
    protected PanelFocusManager(){
    }
    
    
    public static PanelFocusManager get() {
        if (focusManager == null){
            focusManager = new PanelFocusManager();
        }
        return focusManager;
    }
    
    @Override
    protected FocusImpl getImpl() {
        return FocusImpl.getFocusImplForPanel();
    }

    /*
     * FIXME precisamos de uma implementação diferente para gecko1.9 e Safari, 
     *       pois onblur e onfocus não são disparados em DIV
     */
    public void makeDivFocusable(DivElement element){
        if (getImpl() instanceof FocusImplOld){
            makeFocusable((FocusImplOld) getImpl(), element);
        }
    }
    
    @Override
    public void onPostCreate(Widget widget) {
        super.onPostCreate(widget);
        Element element = getFocusableElement(widget);
        if (element.getTagName().equalsIgnoreCase("div")){
            makeDivFocusable(DivElement.as(element));
        }
    }

    protected native void makeFocusable(FocusImplOld impl, DivElement div) /*-{
        var input = impl.@com.google.gwt.user.client.ui.impl.FocusImplOld::createHiddenInput()();
        input.addEventListener(
          'blur',
          impl.@com.google.gwt.user.client.ui.impl.FocusImplOld::blurHandler,
          false);

        input.addEventListener(
          'focus',
          impl.@com.google.gwt.user.client.ui.impl.FocusImplOld::focusHandler,
          false);

        div.addEventListener(
          'mousedown',
          impl.@com.google.gwt.user.client.ui.impl.FocusImplOld::mouseHandler,
          false);

        div.appendChild(input);
    }-*/;

    /*
    public Element createHiddenFocusElement(){
        InputElement element = Document.get().createTextInputElement();
        element.setPropertyString("type", "text");
        element.setClassName(Dijit.getTheme().dijitHiddenFocusName());
        return element;
    }

    @Override
    protected Element getFocusableElement(Widget widget) {
        Element focusableElement = widget.getAttachedElement("focusableElement", null);
        if (focusableElement == null){
            throw new DojoRuntimeException(this, "target widget has no \"focusableElement\" attached!");
        }
        return focusableElement;
    }

    @Override
    public void onPostCreate(Widget widget) {
        super.onPostCreate(widget);
        JsMap<Object> focusableElement = getFocusableElement(widget).cast();
        focusableElement.set(OWNER_WIDGET_PROPERTY, widget);
        focusableElement.set("onfocus", nativeHandler);
        focusableElement.set("onblur", nativeHandler);
        widget.sinkEvents(Event.ONKEYDOWN | Event.ONMOUSEDOWN | Event.ONFOCUS | Event.ONBLUR);
    }
    
    public void onBrowserEvent(Widget widget, Event event) {
        boolean canFireEvent = false;
        switch (event.getTypeInt()){

            case Event.ONFOCUS: {
                Console.log("manager-FOCUS");
                Element focusableElement = getFocusableElement(widget);
                focusableElement.<JsMap<Event>>cast().set(LAST_FOCUS_EVENT_PROPERTY, event);
                canFireEvent = focusableElement.getPropertyInt(WAITING_PROPERTY) == WAINTING_FOR_FOCUS;
                if (canFireEvent){
                    focusableElement.setPropertyInt(WAITING_PROPERTY, 0);
                }
                canFireEvent = setFocusedWidget(widget) || canFireEvent;
            }
            
            case Event.ONBLUR: {
                Console.log("manager-BLUR");
                Element focusableElement = getFocusableElement(widget);
                focusableElement.<JsMap<Event>>cast().set(LAST_BLUR_EVENT_PROPERTY, event);
                canFireEvent = focusableElement.getPropertyInt(WAITING_PROPERTY) == WAINTING_FOR_BLUR;
                if (canFireEvent){
                    focusableElement.setPropertyInt(WAITING_PROPERTY, 0);
                }
            }
            
        }
        event.stopPropagation();
        if (canFireEvent){
            widget.onBrowserEvent(event);
        }
    }

    private boolean setFocusedWidget(Widget widget) {
        if (focusedWidget != null){
            if (focusedWidget.equals(widget)){
                return false;
            }
            fireFocusEvent(focusedWidget, false);
        }
        focusedWidget = widget;
        return true;
    }

    private void fireFocusEvent(Widget widget, boolean focused) {
        Element focusableElement = super.getFocusableElement(widget);
        JsMap<Event> map = focusableElement.cast();
        
        if (!JsUtil.absEquals(map.get(OWNER_WIDGET_PROPERTY), widget)){            
            // Oops! This widget does not use this manager...
            return;
        }
        
        Console.log("manager-fire-" + focused);
        if (focused){
            Event event = map.get(LAST_FOCUS_EVENT_PROPERTY);
            if (event != null){
                widget.onBrowserEvent(event);
                return;
            }
            focusableElement.setPropertyInt(WAITING_PROPERTY, WAINTING_FOR_FOCUS);
        } else {
            Event event = map.get(LAST_BLUR_EVENT_PROPERTY);
            if (event != null){
                widget.onBrowserEvent(event);
                return;
            }
            focusableElement.setPropertyInt(WAITING_PROPERTY, WAINTING_FOR_BLUR);
        }
        
        super.setFocus(widget, focused);
    }
    
    
    public boolean hasFocus(Widget widget){
        return Dojo.isEquals(focusedWidget, widget);
    }

    
    public Widget getFocusedWidget(){
        return focusedWidget;
    }
    
    @Override
    protected native void initializeEngine() /*-{
        var self = this;
        var wp = @com.googlecode.dgwt.client.dijit.base.focus.PanelFocusManager::OWNER_WIDGET_PROPERTY;
        self.@com.googlecode.dgwt.client.dijit.base.focus.PanelFocusManager::nativeHandler = function(e){
            e = e || $wnd.event;
            if (e){
                self.@com.googlecode.dgwt.client.dijit.base.focus.PanelFocusManager::onBrowserEvent(Lcom/googlecode/dgwt/client/dijit/Widget;Lcom/google/gwt/user/client/Event;)(this[wp], e);
            }
        };
        var f = function(e){
            e = e || $wnd.event;
            if (e){
                self.@com.googlecode.dgwt.client.dijit.base.focus.PanelFocusManager::onDocumentEvent(Lcom/google/gwt/user/client/Event;)(e);
            }
        };
        // FIXME : fazer impl independente, não usar dojo.connect
        dojo.connect($doc.body, "onmousedown", f);
        dojo.connect($doc.body, "onkeydown", f);
        dojo.connect($doc.body, "onkeyup", f);
    }-*/;
/*
    protected void onDocumentEvent(Event event) {
        EventTarget target = event.getEventTarget();
        
        if (target != null 
                && Node.is(target)){
            Node node = target.cast();
            
            do {
                if (Element.is(node)){
                    String widgetid = node.<Element>cast().getAttribute(Widget.WIDGET_ID);
                    
                    if (widgetid != null 
                            && widgetid.startsWith(widgetid)){
                        Widget widget = Dijit.byNode(node);
                        
                        if (widget != null){
                            if (setFocusedWidget(widget)){
                                Console.log("manager-external-" + true + "::" + widget.getStyleName());
                                fireFocusEvent(widget, true);
                            }
                            else Console.log("manager-external-" + false + "::" + widget.getStyleName());
                            return;
                        }
                    }
                }
                node = node.getParentNode();
            } while (node != null);
            Console.log("manager-external-none!!!");
        }
    }
    */
}
